package com.liyunc.socket.webclient.util;

import com.liyunc.socket.webclient.logger.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Request {

    private InputStream input;//输入流
    private String request;//请求字符串，请求路径、参数、协议、版本。。。
    private String url;//请求uri
    private String method;//请求方法
    private final Map<String, List<String>> paramMap;//参数

    private static final String CRLF = "\r\n";//换行
    private static final String BLANK = "";//空格
    private static final String METHOD_GET = "GET";
    private static final String METHOD_POST = "POST";
    private static final int CAPACITY = 2048;

    public Request() {
        request = BLANK;
        url = BLANK;
        method = BLANK;
        paramMap = new HashMap<>();
    }

    public Request(InputStream inputStream) {
        this();
        this.input = inputStream;
        this.parse();
    }

    /**
     * requestString形式如下：
     * GET /index.html HTTP/1.1
     * Host: localhost:8080
     * Connection: keep-alive
     * Cache-Control: max-age=0
     * ...
     * 该函数目的就是为了获取/index.html字符串
     */
    public void parse() {
        StringBuilder requestInfo = new StringBuilder(CAPACITY);
        byte[] buffer = new byte[CAPACITY];
        int len;
        try {
            len = input.read(buffer);
        } catch (IOException e) {
            Logger.error(e.toString());
            len = -1;
        }
        for (int i = 0; i < len; i++) {
            requestInfo.append((char) buffer[i]);
        }
        request = requestInfo.toString();
        this.parseInfo(request);
    }

    //从inputStream中读取request信息，并从中获取url值
    private void parseInfo(String request) {
        if (request.isEmpty()) {
            return;
        }
        String params = "";
        // 获取请求参数第一行，从零开始到第一个换行位置
        String firstLine = request.substring(0, request.indexOf(CRLF)).trim();
        // 分解出请求方式
        int index = firstLine.indexOf("/");
        this.method = firstLine.substring(0, index).trim();
        // 分解出url
        String tempUrl = firstLine.substring(index, firstLine.indexOf("HTTP/")).trim();
        // GET请求url格式： http://host:port/path?xxx=aaa&ooo=bbb
        if (METHOD_GET.equalsIgnoreCase(this.method)) {
            if (tempUrl.contains("?")) {
                String[] urlArray = tempUrl.split("\\?", 2);
                this.url = urlArray[0];
                params = urlArray[1];
            } else {
                this.url = tempUrl;
            }
        } else {
            this.url = tempUrl;
            params = request.substring(request.lastIndexOf(CRLF)).trim();
        }
        Logger.info("//path: " + url);
        if (params.isEmpty()) {
            Logger.info("//param: 参数为空");
            return;
        }
        this.parseParam(params);
    }

    private void parseParam(String params) {
        String[] token = params.split("&");
        for (String keyValues : token) {
            String[] keyValue = keyValues.split("=");
            if (keyValue.length == 1) {
                keyValue = Arrays.copyOf(keyValue, 2);
                keyValue[1] = null;
            }
            //将表单对应的k-v存储到map中
            String key = keyValue[0].trim();
            String value = keyValue[1] == null ? null : decode(keyValue[1].trim());

            //放入到集合中
            if (!paramMap.containsKey(key)) {
                paramMap.put(key, new ArrayList<>());
            }
            List<String> values = paramMap.get(key);
            values.add(value);
        }
        Logger.info("//param: " + paramMap);
    }

    public String getParameter(String name) {
        String[] values = this.getParameters(name);
        if (values == null) {
            return null;
        } else {
            return values[0];
        }
    }

    public String[] getParameters(String name) {
        List<String> values = paramMap.get(name);
        if (values == null) {
            return null;
        } else {
            return values.toArray(new String[0]);
        }
    }

    private String decode(String value) {
        try {
            return URLDecoder.decode(value, "utf-8");
        } catch (UnsupportedEncodingException e) {
            Logger.error(e.toString());
        }
        return null;
    }

    public String getUrl() {
        return url;
    }
}
